package com.huawei.fakedouyin.util;

import static androidx.lifecycle.Lifecycle.State.DESTROYED;
import static androidx.lifecycle.Lifecycle.State.STARTED;

import android.os.Looper;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.Observer;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Executor;

/**
 * 作者: 王业通（wytaper495@qq.com）
 * 日期: {2023/5/4 13:07}
 * 备注:
 */
public class LiveEventData<T> {

    private T mData;
    private final Map<Observer, ObserverWrapper> observers = new HashMap<>();

    /**
     * 空构造函数
     */
    public LiveEventData() {
    }

    /**
     *
     * @param data 监听的对象
     */
    public LiveEventData(T data) {
        this.mData = data;
    }

    /**
     *
     * @param data 数据改变
     */
    public void set(T data) {
        this.mData = data;
        synchronized (observers) {
            for (Observer observer : observers.values()) {
                observer.onChanged(data);
            }
        }
    }

    /**
     *
     * @param data 数据改变
     */
    public void postValue(T data) {
        set(data);
    }

    /**
     *
     * @return 当前数据值
     */
    public T get() {
        return mData;
    }

    /**
     * @param owner LifecycleOwner
     * @param observe 主线程监听
     */
    public void observe(LifecycleOwner owner, Observer<? super T> observe) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observe, this);
        internalObserve(observe, wrapper);
        owner.getLifecycle().addObserver(wrapper);
    }

    /**
     *
     * @param observe 所在线程监听
     */
    public void observeForever(Observer<? super T> observe) {
        observeForever(null, observe);
    }

    /**
     * @param observe executor线程监听
     * @param executor 所在线程
     */
    public void observeForever(Executor executor, Observer<? super T> observe) {
        internalObserve(observe, new ObserverWrapper(observe, executor));
    }

    private void internalObserve(Observer observe, ObserverWrapper wrapper) {
        observers.put(observe, wrapper);
    }

    /**
     *
     * @param observer 移除监听
     */
    public void removeObserver(final Observer<? super T> observer) {
        ObserverWrapper wrapper = observers.remove(observer);
        if (wrapper != null && wrapper instanceof LifecycleBoundObserver) {
            ((LifecycleBoundObserver) wrapper).mOwner.getLifecycle().removeObserver((LifecycleObserver) wrapper);
        }
    }

    /**
     *
     * @param owner 移除owner所有监听
     */
    public void removeObservers(final LifecycleOwner owner) {
        for (Iterator<ObserverWrapper> iter = observers.values().iterator(); iter.hasNext(); ) {
            ObserverWrapper wrapper = iter.next();
            if (wrapper instanceof LifecycleBoundObserver && ((LifecycleBoundObserver) wrapper).mOwner == owner) {
                ((LifecycleBoundObserver) wrapper).mOwner.getLifecycle().removeObserver((LifecycleObserver) wrapper);
                iter.remove();
            }
        }
    }

    static class ObserverWrapper implements Observer, Runnable {
        final Observer observer;
        final Executor executor;
        Object pendingValue;
        long dataVersion;
        long dispatchedVersion;

        private ObserverWrapper(Observer observer, Executor executor) {
            this.observer = observer;
            this.executor = executor;
        }

        @Override
        public void onChanged(Object obj) {
            synchronized (this) {
                dataVersion++;
                pendingValue = obj;
                if (executor == null) {
                    run();
                } else {
                    executor.execute(this);
                }
            }
        }

        @Override
        public void run() {
            if (dispatchedVersion != dataVersion) {
                synchronized (this) {
                    if (dispatchedVersion != dataVersion) {
                        dispatchedVersion = dataVersion;
                        observer.onChanged(pendingValue);
                    }
                }
            }
        }
    }

    static class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        final LifecycleOwner mOwner;
        final LiveEventData liveEventData;

        LifecycleBoundObserver(LifecycleOwner owner, Observer observer, LiveEventData liveEventData) {
            super(observer, MainExecutor.get());
            mOwner = owner;
            this.liveEventData = liveEventData;
        }

        @Override
        public void run() {
            if (shouldBeActive()) {
                super.run();
            }
        }

        boolean shouldBeActive() {
            Lifecycle.State state = mOwner.getLifecycle().getCurrentState();
            return state.isAtLeast(STARTED) && state != DESTROYED;
        }

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
            if (currentState == DESTROYED) {
                liveEventData.removeObserver(observer);
                return;
            }
            run();
        }
    }

    static void assertMainThread(String methodName) {
        if (Looper.getMainLooper() != Looper.myLooper()) {
            throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
                    + " thread");
        }
    }
}
